// file: inventory.ts

import { IItem, ISlot } from './inventory.types';
import { EventEmitter } from './event.emitter';

/**
 * 定义背包系统可能发出的所有事件及其负载类型。
 */
type InventoryEvents = {
    /** 当整个背包内容需要刷新时触发 */
    refreshed: { slots: readonly ISlot[] };
    /** 当某个特定槽位更新时触发 */
    slot_updated: { index: number; slot: ISlot };
};

/**
 * 纯数据逻辑的背包系统。
 */
export class Inventory {
    private _slots: ISlot[];
    public readonly events = new EventEmitter<InventoryEvents>();

    /**
     * @param size 背包的容量（槽位数量）
     */
    constructor(public readonly size: number) {
        this._slots = Array.from({ length: size }, () => ({
            item: null,
            quantity: 0,
            durable: 0,
        }));
    }

    /**
     * 获取所有槽位的只读副本。
     * @returns {readonly ISlot[]}
     */
    public get slots(): readonly ISlot[] {
        return this._slots;
    }

    /**
     * 向背包中添加物品。
     * @param itemToAdd 要添加的物品类型
     * @param quantity 要添加的数量
     * @returns {number} 无法添加的剩余物品数量（0表示全部成功添加）
     */
    public addItem(itemToAdd: IItem, quantity: number): number {
        let remainingQuantity = quantity;

        // 阶段1: 填充已有的、未满的同类物品堆叠
        for (let i = 0; i < this.size; i++) {
            const slot = this._slots[i];
            if (
                slot.item?.id === itemToAdd.id &&
                slot.quantity < slot.item.maxStack
            ) {
                const canAdd = slot.item.maxStack - slot.quantity;
                const amountToAdd = Math.min(remainingQuantity, canAdd);
                slot.quantity += amountToAdd;
                remainingQuantity -= amountToAdd;
                this.events.emit('slot_updated', {
                    index: i,
                    slot: { ...slot },
                });
                if (remainingQuantity === 0) return 0;
            }
        }

        // 阶段2: 寻找空槽位放置新物品
        for (let i = 0; i < this.size; i++) {
            const slot = this._slots[i];
            if (slot.item === null) {
                const amountToAdd = Math.min(
                    remainingQuantity,
                    itemToAdd.maxStack,
                );
                slot.item = itemToAdd;
                slot.quantity = amountToAdd;
                remainingQuantity -= amountToAdd;
                this.events.emit('slot_updated', {
                    index: i,
                    slot: { ...slot },
                });
                if (remainingQuantity === 0) return 0;
            }
        }

        // 如果还有剩余，说明背包已满
        return remainingQuantity;
    }

    /**
     * 从指定槽位移除一定数量的物品。
     * @param index 槽位索引
     * @param quantity 要移除的数量
     * @returns {boolean} 是否成功移除了指定数量
     */
    public removeItem(index: number, quantity: number): boolean {
        if (
            !this.isValidIndex(index) ||
            this._slots[index].item === null ||
            this._slots[index].quantity < quantity
        ) {
            return false; // 索引无效或物品不足
        }

        const slot = this._slots[index];
        slot.quantity -= quantity;

        if (slot.quantity <= 0) {
            slot.item = null;
            slot.quantity = 0;
        }

        this.events.emit('slot_updated', { index, slot: { ...slot } });
        return true;
    }

    /**
     * 移动槽位中的物品（拖拽逻辑的核心）。
     * @param fromIndex 起始槽位索引
     * @param toIndex 目标槽位索引
     */
    public moveItem(fromIndex: number, toIndex: number): void {
        if (
            !this.isValidIndex(fromIndex) ||
            !this.isValidIndex(toIndex) ||
            fromIndex === toIndex
        ) {
            return;
        }

        const fromSlot = this._slots[fromIndex];
        const toSlot = this._slots[toIndex];

        if (fromSlot.item === null) return; // 起始槽为空

        // 目标槽不为空，且物品ID相同，尝试合并
        if (
            toSlot.item?.id === fromSlot.item.id &&
            toSlot.quantity < toSlot.item.maxStack
        ) {
            const canAdd = toSlot.item.maxStack - toSlot.quantity;
            const amountToMove = Math.min(fromSlot.quantity, canAdd);

            toSlot.quantity += amountToMove;
            fromSlot.quantity -= amountToMove;

            if (fromSlot.quantity <= 0) {
                fromSlot.item = null;
                fromSlot.quantity = 0;
            }
        } else {
            // 否则，直接交换两个槽位的内容
            [this._slots[fromIndex], this._slots[toIndex]] = [
                this._slots[toIndex],
                this._slots[fromIndex],
            ];
        }

        // 通知更新
        this.events.emit('slot_updated', {
            index: fromIndex,
            slot: { ...this._slots[fromIndex] },
        });
        this.events.emit('slot_updated', {
            index: toIndex,
            slot: { ...this._slots[toIndex] },
        });
    }

    /**
     * 强制刷新整个背包的UI（例如，打开背包时调用）。
     */
    public forceRefresh(): void {
        this.events.emit('refreshed', { slots: this.slots });
    }

    private isValidIndex(index: number): boolean {
        return index >= 0 && index < this.size;
    }
}
